package ast

import (
	"bytes"
	"gum/interpreter/token"
	"strings"
)

type Node interface {
	NodeLiteral() string
}

type Expression interface {
	Node
	expression()
}

type Statement interface {
	Node
	statement()
}

type Program struct {
	Statements []Statement
}

func (p *Program) NodeLiteral() string {
	ret := strings.Builder{}
	for _, statement := range p.Statements {
		ret.WriteString(statement.NodeLiteral())
	}
	return ret.String()
}

type BlockStatement struct {
	statements []Statement
}

func (b *BlockStatement) NodeLiteral() string {
	ret := strings.Builder{}
	for _, statement := range b.statements {
		ret.WriteString(statement.NodeLiteral())
	}
	return ret.String()
}

func (b *BlockStatement) statement() {}

type LetStatement struct {
	Symbol Node
	Value  Expression
}

func (s *LetStatement) NodeLiteral() string {
	ret := strings.Builder{}
	ret.WriteString("let ")
	ret.WriteString(s.Symbol.NodeLiteral())
	ret.WriteString(" = ")
	ret.WriteString(s.Value.NodeLiteral())
	ret.WriteString(";")
	return ret.String()
}

func (s *LetStatement) statement() {}

type ReturnStatement struct {
	Value Expression
}

func (s *ReturnStatement) NodeLiteral() string {
	ret := strings.Builder{}
	ret.WriteString("return ")
	ret.WriteString(s.Value.NodeLiteral())
	ret.WriteString(";")
	return ret.String()
}

func (s *ReturnStatement) statement() {}

type ExpressionStatement struct {
	Value Expression
}

func (e *ExpressionStatement) NodeLiteral() string {
	ret := strings.Builder{}
	ret.WriteString(e.Value.NodeLiteral())
	ret.WriteString(";")
	return ret.String()
}

func (e *ExpressionStatement) statement() {}

type Identifier struct {
	Name string
	*token.Token
}

func (i *Identifier) NodeLiteral() string {
	return i.Name
}

func (i *Identifier) expression() {}

type Digits struct {
	Name string
	*token.Token
}

func (d *Digits) NodeLiteral() string {
	return d.Name
}

func (d *Digits) expression() {}

type InfixExpression struct {
	Operator string
	Left     Expression
	Right    Expression
}

func (i *InfixExpression) NodeLiteral() string {
	var buf bytes.Buffer
	buf.WriteString(i.Left.NodeLiteral())
	buf.WriteString(" " + i.Operator + " ")
	buf.WriteString(i.Right.NodeLiteral()) // expression一律不添加；
	return buf.String()
}

func (i *InfixExpression) expression() {}

type GroupExpression struct {
	Value Expression
}

func (g *GroupExpression) NodeLiteral() string {
	var buf bytes.Buffer
	buf.WriteString("(")
	buf.WriteString(g.Value.NodeLiteral()) // expression一律不添加；
	buf.WriteString(")")
	return buf.String()
}

func (g *GroupExpression) expression() {}
